package ann;

import java.util.ArrayList;
import java.util.List;

import topology.OneToOne;
import topology.Topology;

import activation.Linear;
import learning.LearningRule;

public abstract class Module{

	private SubNetwork parent;
	private List<Link> inputLinks;
	private List<Link> outputLinks;
	private Layer biasLayer;
	
	public Module()
	{
		parent = null;
		
		outputLinks = new ArrayList<Link>();
		inputLinks = new ArrayList<Link>();
	}
	
	public abstract void setInput(int i, double j);
	public abstract void incrementInput(int i, double j);
	
	public final void setParent(SubNetwork parent){
		this.parent = parent;
	}
	public final SubNetwork getParent(){
		return parent;
	}
	
	public abstract int getInputSize();
	public abstract int getOutputSize();
	
	public final void addOutputLink(Link link){
		outputLinks.add(link);
	}
	public final void addInputLink(Link link){
		inputLinks.add(link);
	}
	
	public abstract void updateInput();
	
	protected final List<Link> getTotalInputLinks(){
		if(parent != null && parent.getFirstSubModule() == this)
			return parent.getTotalInputLinks();
		return inputLinks;
	}
	protected final List<Link> getTotalOutputLinks(){
		if(parent != null && parent.getLastSubModule() == this)
			return parent.getTotalOutputLinks();
		return outputLinks;
	}
	
	public abstract double getOutput(int index);
	
	public abstract void updateOutput();
	
	public abstract void setTarget(int index, double target);
	
	public abstract void propagateError();
	public abstract void clearInError();
	public abstract void updateOutError();
	public abstract double getInError(int toIndex);
	public abstract void incrementOutError(int index,double increment);
	
	public abstract void incrementWeightDeltas();
	public abstract void addWeightDeltas();
	
	public abstract Module getFirstLayer();
	public abstract Module getLastLayer();
	public final List<Link> getInputLinks(){
		return inputLinks;
	}
	public final List<Link> getOutputLinks(){
		return outputLinks;
	}
	public final void addBiasLayer(LearningRule learningRule,double learningRate,double minInitialWeight,double maxInitialWeight,double momentumRate){
		biasLayer = new Layer(this.getInputSize(),new Linear(), "BiasLayer");
		for(int i  = 0; i < this.getInputSize(); i++)
			biasLayer.setInput(i, 1);
		biasLayer.updateOutput();
		Link.setupLink(biasLayer,this,new OneToOne(),learningRule,learningRate,minInitialWeight,maxInitialWeight,momentumRate);
	}

	public Module getBiasLayer() {
		return biasLayer;
	}
}
